/*
 * @(#)ParallelSolver.java
 */
package jp.ac.kobe_u.cs.cream;

import jp.ac.kobe_u.cs.cream.*;
import java.util.*;

public class ParallelSolver extends Solver implements SolutionHandler {
    protected Solver solvers[];

    public ParallelSolver(Solver solvers[]) {
	this(solvers, null);
    }

    public ParallelSolver(Solver solvers[], String name) {
	super(null, NONE, name);
	this.solvers = solvers;
	network = solvers[0].network;
	option = solvers[0].option;
    }

    public void setMonitor(Monitor monitor) {
	for (int i = 0; i < solvers.length; i++) {
	    solvers[i].setMonitor(monitor);
	}
    }

    public synchronized void stop() {
	for (int i = 0; i < solvers.length; i++) {
	    solvers[i].stop();
	}
	super.stop();
    }

    public synchronized void solved(Solver solver, Solution solution) {
	if (isAborted() || solution == null) {
	    return;
	}
	int oldBestValue = bestValue;
	this.solution = solution;
	success();
	if (! (solver instanceof LocalSearch))
	    return;
	if (network.getObjective() == null)
	    return;
	int value = solution.getObjectiveIntValue();
	if (! isBetter(value, oldBestValue)) {
	    double rate = 0.0;
	    if (solver instanceof LocalSearch) {
		rate = ((LocalSearch)solver).getExchangeRate();
	    }
	    if (Math.random() < rate) {
		//System.out.println(header + "Get " + best);
		((LocalSearch)solver).setCandidate(bestSolution);
	    }
	}
    }

    private void allStart() {
	for (int i = 0; i < solvers.length; i++) {
	    synchronized (solvers[i]) {
		if (solvers[i] != null) {
		    solvers[i].start(this, totalTimeout);
		}
	    }
	}
    }

    private void allJoin() {
	// Add synchronized statement
	// Modified by Muneyuki Kawatani 05/12/09
	synchronized (solvers) {
	    for (int i = 0; i < solvers.length; i++) {
		synchronized (solvers[i]) {
		    if (solvers[i] != null) {
			solvers[i].join();
		    }
		}
	    }
	}
    }

    public void run() {
	clearBest();
	allStart();
	allJoin();
	fail();
    }
}
